Implement sloped caret drawing
authorMatthias Clasen <mclasen@redhat.com>
Mon, 23 Aug 2021 21:39:04 +0000 (17:39 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Wed, 25 Aug 2021 10:53:53 +0000 (06:53 -0400)
Prepare for Pango to return slope information for carets.

While we are at it, improve the shape of our carets a bit.

gtk/gtkstylecontext.c

index 4ded60230c83224f4c6c39e8736afd546dc4db9d..2642106bf0be485e8722e4502ff79d3ea4f496c7 100644 (file)
@@ -972,6 +972,7 @@ draw_insertion_cursor (GtkStyleContext *context,
                        cairo_t         *cr,
                        double           x,
                        double           y,
+                       double           width,
                        double           height,
                        double           aspect_ratio,
                        gboolean         is_primary,
@@ -981,7 +982,8 @@ draw_insertion_cursor (GtkStyleContext *context,
   GdkRGBA primary_color;
   GdkRGBA secondary_color;
   int stem_width;
-  int offset;
+  double angle;
+  double dx, dy;
 
   cairo_save (cr);
   cairo_new_path (cr);
@@ -990,107 +992,104 @@ draw_insertion_cursor (GtkStyleContext *context,
   gdk_cairo_set_source_rgba (cr, is_primary ? &primary_color : &secondary_color);
 
   stem_width = height * aspect_ratio + 1;
+  if (width < 0)
+    stem_width = - stem_width;
 
-  /* put (stem_width % 2) on the proper side of the cursor */
-  if (direction == PANGO_DIRECTION_LTR)
-    offset = stem_width / 2;
-  else
-    offset = stem_width - stem_width / 2;
+  angle = atan (height / width);
 
-  cairo_rectangle (cr, x - offset, y, stem_width, height);
-  cairo_fill (cr);
+  dx = (stem_width/2.0) * cos (M_PI/2 - angle);
+  dy = (stem_width/2.0) * sin (M_PI/2 - angle);
 
   if (draw_arrow)
     {
-      int arrow_width;
-      int ax, ay;
-
-      arrow_width = stem_width + 1;
-
       if (direction == PANGO_DIRECTION_RTL)
         {
-          ax = x - offset - 1;
-          ay = y + height - arrow_width * 2 - arrow_width + 1;
+          double x0, y0, x1, y1, x2, y2;
 
-          cairo_move_to (cr, ax, ay + 1);
-          cairo_line_to (cr, ax - arrow_width, ay + arrow_width);
-          cairo_line_to (cr, ax, ay + 2 * arrow_width);
-          cairo_fill (cr);
+          x0 = x - dx + 2 * dy;
+          y0 = y + height - dy - 2 * dx;
+
+          x1 = x0 + 4 * dy;
+          y1 = y0 - 4 * dx;
+          x2 = x0 + 2 * dy - 3 * dx;
+          y2 = y0 - 2 * dx - 3 * dy;
+
+          cairo_move_to (cr, x + width + dx, y + dy);
+          cairo_line_to (cr, x + dx, y + height + dy);
+          cairo_line_to (cr, x2, y2);
+          cairo_line_to (cr, x1, y1);
+          cairo_line_to (cr, x + width - dx, y - dy);
         }
       else if (direction == PANGO_DIRECTION_LTR)
         {
-          ax = x + stem_width - offset;
-          ay = y + height - arrow_width * 2 - arrow_width + 1;
+          double x0, y0, x1, y1, x2, y2;
+
+          x0 = x + dx + 2 * dy;
+          y0 = y + height + dy - 2 * dx;
 
-          cairo_move_to (cr, ax, ay + 1);
-          cairo_line_to (cr, ax + arrow_width, ay + arrow_width);
-          cairo_line_to (cr, ax, ay + 2 * arrow_width);
-          cairo_fill (cr);
+          x1 = x0 + 4 * dy;
+          y1 = y0 - 4 * dx;
+          x2 = x0 + 2 * dy + 3 * dx;
+          y2 = y0 - 2 * dx + 3 * dy;
+
+          cairo_move_to (cr, x + width - dx, y - dy);
+          cairo_line_to (cr, x - dx, y + height - dy);
+          cairo_line_to (cr, x2, y2);
+          cairo_line_to (cr, x1, y1);
+          cairo_line_to (cr, x + width + dx, y + dy);
         }
       else
         g_assert_not_reached();
     }
+  else
+    {
+      cairo_move_to (cr, x + width + dx, y + dy);
+      cairo_line_to (cr, x + dx, y + height + dy);
+      cairo_line_to (cr, x - dx, y + height - dy);
+      cairo_line_to (cr, x + width - dx, y - dy);
+    }
+
+  cairo_fill (cr);
 
   cairo_restore (cr);
 }
 
 static void
-get_insertion_cursor_bounds (double           height,
+get_insertion_cursor_bounds (double           width,
+                             double           height,
                              double           aspect_ratio,
                              PangoDirection   direction,
                              gboolean         draw_arrow,
                              graphene_rect_t *bounds)
 {
   int stem_width;
-  int offset;
 
   stem_width = height * aspect_ratio + 1;
-  if (direction == PANGO_DIRECTION_LTR)
-    offset = stem_width / 2;
-  else
-    offset = stem_width - stem_width / 2;
 
-  if (draw_arrow)
-    {
-      if (direction == PANGO_DIRECTION_LTR)
-        {
-          graphene_rect_init (bounds,
-                              - offset, 0,
-                              2 * stem_width + 1, height);
-        }
-      else
-        {
-          graphene_rect_init (bounds,
-                              - offset - stem_width - 2, 0,
-                              2 * stem_width + 2, height);
-        }
-    }
-  else
-    {
-      graphene_rect_init (bounds,
-                          - offset, 0,
-                          stem_width, height);
-    }
+  graphene_rect_init (bounds,
+                      - 2 * stem_width, - stem_width,
+                      width + 4 * stem_width, height + 2 * stem_width);
 }
 
 static void
 snapshot_insertion_cursor (GtkSnapshot     *snapshot,
                            GtkStyleContext *context,
+                           double           width,
                            double           height,
                            double           aspect_ratio,
                            gboolean         is_primary,
                            PangoDirection   direction,
                            gboolean         draw_arrow)
 {
-  if (draw_arrow)
+  if (width != 0 || draw_arrow)
     {
       cairo_t *cr;
       graphene_rect_t bounds;
 
-      get_insertion_cursor_bounds (height, aspect_ratio, direction, draw_arrow, &bounds);
+      get_insertion_cursor_bounds (width, height, aspect_ratio, direction, draw_arrow, &bounds);
       cr = gtk_snapshot_append_cairo (snapshot, &bounds);
 
-      draw_insertion_cursor (context, cr, 0, 0, height, aspect_ratio, is_primary, direction, draw_arrow);
+      draw_insertion_cursor (context, cr, 0, 0, width, height, aspect_ratio, is_primary, direction, draw_arrow);
 
       cairo_destroy (cr);
     }
@@ -1193,6 +1192,7 @@ gtk_snapshot_render_insertion_cursor (GtkSnapshot     *snapshot,
   gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x + PANGO_PIXELS (cursor1->x), y + PANGO_PIXELS (cursor1->y)));
   snapshot_insertion_cursor (snapshot,
                              context,
+                             PANGO_PIXELS (cursor1->width),
                              PANGO_PIXELS (cursor1->height),
                              aspect_ratio,
                              TRUE,
@@ -1206,6 +1206,7 @@ gtk_snapshot_render_insertion_cursor (GtkSnapshot     *snapshot,
       gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x + PANGO_PIXELS (cursor2->x), y + PANGO_PIXELS (cursor2->y)));
       snapshot_insertion_cursor (snapshot,
                                  context,
+                                 PANGO_PIXELS (cursor2->width),
                                  PANGO_PIXELS (cursor2->height),
                                  aspect_ratio,
                                  FALSE,